package main

import (
	"fmt"
	"github.com/zeromicro/go-zero/core/conf"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
	"gozero-demo/internal/config"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"text/template"
)

const repoDir = "./internal/repo/mysql"
const repoTestDir = "./internal/repo/mysql_test"

// toCamelCase 将下划线分隔的字符串转换为驼峰命名
func toCamelCase(s string) string {
	parts := strings.Split(s, "_")
	var result strings.Builder
	for _, part := range parts {
		if len(part) > 0 {
			result.WriteString(strings.ToUpper(part[:1]) + part[1:])
		}
	}
	return result.String()
}

func generateRepoFile(baseName string) error {
	// 生成文件名
	fileName := strings.ToLower(baseName) + "_repo.go"
	filePath := filepath.Join(repoDir, fileName)

	// 检查文件是否存在
	if _, err := os.Stat(filePath); err == nil {
		fmt.Printf("File %s already exists, skipping generation.\n", filePath)
		return nil
	}

	// 创建文件
	file, err := os.Create(filePath)
	if err != nil {
		return fmt.Errorf("failed to create file %s: %v", filePath, err)
	}
	defer func(file *os.File) {
		err := file.Close()
		if err != nil {
			fmt.Printf("Failed to close file %s: %v\n", filePath, err)
		}
	}(file)

	// 生成 repo 名称
	repoName := toCamelCase(baseName)

	// 使用模板生成文件内容
	// 读取模板文件内容
	templateFilePath := "template_files/repo_template.txt"
	_, fileDir, _, _ := runtime.Caller(0)
	templateData, err := os.ReadFile(filepath.Join(fileDir, "../", templateFilePath))
	if err != nil {
		log.Fatalf("repo模板文件读取失败: %s", err)
	}

	// 将字节切片转换为字符串并打印
	repoTemplate := string(templateData)

	tmpl, err := template.New("repo").Parse(repoTemplate)
	if err != nil {
		return fmt.Errorf("failed to parse template: %v", err)
	}

	data := struct {
		RepoName string
	}{
		RepoName: repoName,
	}

	if err := tmpl.Execute(file, data); err != nil {
		return fmt.Errorf("failed to execute template: %v", err)
	}

	fmt.Printf("Successfully generated file %s\n", filePath)
	return nil
}

func generateRepoTestFile(baseName string) error {
	// 生成文件名
	fileName := strings.ToLower(baseName) + "_repo_test.go"
	filePath := filepath.Join(repoTestDir, fileName)

	// 检查文件是否存在
	if _, err := os.Stat(filePath); err == nil {
		fmt.Printf("File %s already exists, skipping generation.\n", filePath)
		return nil
	}

	// 创建文件
	file, err := os.Create(filePath)
	if err != nil {
		return fmt.Errorf("failed to create file %s: %v", filePath, err)
	}
	defer func(file *os.File) {
		err := file.Close()
		if err != nil {
			fmt.Printf("Failed to close file %s: %v\n", filePath, err)
		}
	}(file)

	// 生成 repo 名称
	repoName := toCamelCase(baseName)

	// 使用模板生成文件内容
	// 读取模板文件内容
	templateFilePath := "template_files/repo_test_template.txt"
	_, fileDir, _, _ := runtime.Caller(0)
	templateData, err := os.ReadFile(filepath.Join(fileDir, "../", templateFilePath))
	if err != nil {
		log.Fatalf("repo模板文件读取失败: %s", err)
	}

	// 将字节切片转换为字符串并打印
	repoTemplate := string(templateData)

	tmpl, err := template.New("repo_test").Parse(repoTemplate)
	if err != nil {
		return fmt.Errorf("failed to parse template: %v", err)
	}

	data := struct {
		RepoName string
	}{
		RepoName: repoName,
	}

	if err := tmpl.Execute(file, data); err != nil {
		return fmt.Errorf("failed to execute template: %v", err)
	}

	fmt.Printf("Successfully generated file %s\n", filePath)
	return nil
}

func main() {
	// 初始化go-zero的配置
	var c config.Config
	configFile := config.GetConfigFile("") //调用自定义的GetConfigFile方法，读取当前配置的env信息
	conf.MustLoad(configFile, &c)

	tablePrefix := "" // 表名前缀

	// 连接数据库
	db, _ := gorm.Open(mysql.Open(c.Mysql.DataSource), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			TablePrefix:   tablePrefix, // 表名前缀
			SingularTable: true,        // 使用单数表名，启用该选项，会区分 user 和 users 表为两个不同的数据表
		},
	})

	//获取全部表名
	var tableNames []string
	db.Raw("SHOW TABLES").Scan(&tableNames)

	for _, tableName := range tableNames {
		// 生成 repo 文件
		baseName := strings.TrimPrefix(tableName, tablePrefix)
		if err := generateRepoFile(baseName); err != nil {
			fmt.Printf("Error generating repo file for table %s: %v\n", tableName, err)
		}
		if err := generateRepoTestFile(baseName); err != nil {
			fmt.Printf("Error generating repo test file for table %s: %v\n", tableName, err)
		}
	}
}
